-- @Author: baidwwy
-- @Date:   2018-04-10 22:48:47
-- @Last Modified by:   baidwwy
-- @Last Modified time: 2018-08-19 21:14:22
local function _复制样式(数据,文本,宽度)
    local ret = {}
    for k,v in pairs(数据) do
        ret[k] = v
    end
    ret.x = 0
    ret.内容 = 文本
    ret.宽度 = 宽度
    return ret
end
local function _取文本左边(文本,字符数)
    local i = 1
    local ascii = 0
    local ret = ''
    while true do
        ascii = 文本:byte(i)
        if ascii and 字符数 > 0 then
            if ascii < 127 then
                ret = ret ..文本:sub(i, i)
                i = i+1
                字符数 = 字符数 -1
            else
                字符数 = 字符数 -2
                if 字符数 >= 0 then
                    ret = ret ..文本:sub(i, i+1)
                    i = i+2
                end
            end
        else
                break
        end
    end
    return ret,文本:sub(i)
end

local 丰富文本类 = class()


function 丰富文本类:初始化(...)
    local arg = {...}
    if type(arg[1]) == 'string' then
        self._宽度 = arg[4] or 400
        self._高度 = arg[5] or 200
    else
        self._宽度 = arg[1] or 400
        self._高度 = arg[2] or 200
    end
    self._默认宽度  = self._宽度
    self._文字   = require("gge文字类")():置行间距(2)
    self._文字宽度,self._文字高度 = self._文字:取宽高("A")
    --self._符号      = "#"
    --self._换行符    = ""
    self._行间距    = 1
    self._元素表    = {W=0xFFFFFFFF}
    self._标识长度  = 1
    self._标识正则  = "(%w)(.*)"

    self._背景精灵  = require("gge精灵类")()

    self._表情位置  = 2
    self._默认颜色  = 0xFFFFFFFF
    self._全局颜色  = nil
    self._默认元素  = 'W'
    self._行数量    = 0
    self._起始值    = 0
    self._目标值    = 0
    self._递增值    = 1

    self._显示表    = {高度 = 0,宽度 = 0}
    self._碰撞表    = {}
    self._原始表    = {}
    self._最大记录  = 1000--最多记录原始条数
    self._最大行数  = 500--最多存放解析行数量
    self._滚动值    = 0 --显示偏移

    self._包围盒    = require("gge包围盒")(0,0,self._宽度,self._高度)
end
--================================================================
function 丰富文本类:置行距(v)
    self._行间距    = v
    return self
end
function 丰富文本类:置宽高(w,h)
    if w~=self._宽度 then
        self._宽度 = w
        self._默认宽度  = self._宽度
        local 原始表 = self._原始表
        self:清空()
        for i,v in ipairs(原始表) do
            self:添加文本(v)
        end
        self:置高度(h)
    else
        self:置高度(h)
    end
end
function 丰富文本类:置高度(v)
    self._高度 = v
    self._包围盒:置宽高(self._宽度,v)
    if self._滚动值~=0 then
        local 范围 = self:取滚动范围()
        if self._滚动值>范围 then
            self._滚动值 = 范围
        end
    end
    self:_计算显示模式()
end
function 丰富文本类:置宽度(v)
    if v~=self._宽度 then
        self._宽度 = v
        self._默认宽度  = self._宽度
        local 原始表 = self._原始表
        self:清空()
        for i,v in ipairs(原始表) do
            self:添加文本(v)
        end
        self:置高度(self._高度)
    end
end
-- function 丰富文本类:置换行符(v)--切行之后,在前面插入一个标志
--     self._换行符   = v or ''
-- end
function 丰富文本类:置默认颜色(v)
    self._默认颜色 = v
end
function 丰富文本类:置颜色(v)--所有文本颜色，取消nil
    self._全局颜色 = v
end
function 丰富文本类:置文字 (v)
    self._文字     = v
    self._文字宽度,self._文字高度 = self._文字:取宽高("A")
    return self
end
function 丰富文本类:置表情位置(v)--1上,2居中
    self._表情位置 = v
end
--================================================================
function 丰富文本类:滚动(v)
    self._滚动值 = self._滚动值-v
    if v == 0 or self._滚动值<0 then--到底
        self._滚动值 = 0
    end
    local 范围 = self:取滚动范围()
    if self._滚动值>范围 then
        self._滚动值 = 范围
    end
    self:_计算显示模式()
    return self._滚动值 == 0
end
function 丰富文本类:取滚动范围()
    local 高度 = 0
    for i,v in ipairs(self._显示表) do
        高度 = 高度 + v.高度+self._行间距
        if 高度>self._高度 then
            return self._行数量-i+1
        end
    end
    return 0
end
function 丰富文本类:滚动到(v)
    self._滚动值 = v
    self:_计算显示模式()
end
function 丰富文本类:滚动到顶()
    self._滚动值 = self:取滚动范围()
    self:_计算显示模式()
end
function 丰富文本类:滚动到底()
    self._滚动值 = 0
    self:_计算显示模式()
end
function 丰富文本类:添加元素(标识,数据,默认)
    标识 = tostring(标识)
    if type(数据) == 'table' then
        数据.标识 = 标识
    end
    if 默认 and type(数据)=='number' then
        self._默认元素 = 标识
    end
    self._元素表[标识] = 数据
    if #标识>self._标识长度 then
        self:置标识长度(#标识)
    end
    return self
end
function 丰富文本类:置标识长度(v)
    self._标识长度 = v
    self._标识正则 = string.format("(%s)(.*)", string.rep('%w?', v))
end
function 丰富文本类:置文本(s)
    self:清空()
    self:添加文本(s)
    return self
end
function 丰富文本类:添加文本(数据,宽度)
    if 数据 then
        table.insert(self._原始表, 数据)
        if #self._原始表>self._最大记录 then
            table.remove(self._原始表, 1)
        end
        数据 = 数据:gsub('##','井\1')
        self._宽度 = 宽度 or self._默认宽度
        for match in (数据.."\n"):gmatch("(.-)\n") do
            if match:sub(1,1)~='#' then
                match = '#'..self._默认元素 .. match
            end
            self:_解析(match.."#")

            if self._行数量 >self._最大行数 then
                table.remove(self._显示表,1)
            end
            self._行数量 = #self._显示表
        end
        self:_计算显示模式()
        return self._显示表.高度,self._显示表.宽度
    end
end
function 丰富文本类:清空()
    self._碰撞表 = {}
    self._原始表 = {}
    self._显示表 = {高度 = 0,宽度 = 0}
    self._行数量 = 0
    return self
end
function 丰富文本类:取原始数据()
    return self._原始表
end
--================================================================
function 丰富文本类:_检查元素(标识)
    if self._元素表[标识] then
        return self._元素表[标识]
    elseif self.取元素 then
        return self:取元素(标识)
    end
    return false
end
function 丰富文本类:_取元素(标识,...)--向元素表查找元素，找不到向用户函数获取
    if self._元素表[标识] then
        return self._元素表[标识]
    elseif self.取元素 then
        return self:取元素(标识,...)
    end
    return self._元素表[self._默认元素]
end
function 丰富文本类:_生成段数据(x,元素,内容)
    local 段数据 = {}
    if type(元素) == 'number' then
        段数据.x    = x
        段数据.颜色 = 元素
        段数据.内容 = 内容:gsub("井\1","#")
        段数据.类型 = 0
        段数据.宽度 = self._文字:取宽度(段数据.内容)
        段数据.高度 = self._文字高度
    elseif 元素 then
        段数据.x    = x
        段数据.内容 = 元素
        段数据.类型 = 1
        段数据.宽度 = 元素.宽度 or 元素:取宽度()
        段数据.高度 = 元素.高度 or 元素:取高度()
    else
        段数据.x    = 0
        段数据.类型 = -1
        段数据.宽度 = 0
        段数据.高度 = 0
    end
    return 段数据
end
function 丰富文本类:_生成样式(段数据,内容)
    local 样式,值 = 内容:match("(%l*)|?(.*)")
    if 样式 == 'xx' then --下划线
        段数据.下划线   = true
    elseif 样式 == 'sx' then --删除线
        段数据.删除线   = true
    elseif 样式 == 'bj' then --背景颜色
        段数据.背景颜色 = self:_取元素(值)
    elseif 样式 == 'pz' then --焦点文字颜色
        段数据.碰撞颜色 = self:_取元素(值)
    elseif 样式 == 'pb' then --焦点背景颜色
        段数据.碰撞背色 = self:_取元素(值)
    elseif 样式 == 'ht' then --回调标识
        段数据.回调  = 值
    elseif 样式 == 'djy' then --段居右
        段数据.居右 = true
    elseif 样式 == 'an' then--文字按钮
        段数据.按钮 = true
    elseif 样式 == 'n' then--换行  #W/n/人物经验|宠物经验
        段数据.换行 = true
    elseif 样式 == 'ss' then--闪烁
        段数据.闪烁时间 = 0
    elseif 样式 == 'zdy' then--将文本传到自定义元素
        段数据.自定义 = true
    elseif 样式 ~="jz" and 样式 ~="jy" and 段数据.类型 == 0 then--文本
        if 段数据.换行 then
            local t = {}
            for match in (内容.."|"):gmatch("(.-)|") do
                if match == '' then
                    t[#t] = t[#t] .. '|'
                else
                    table.insert(t,match)
                end
            end
            段数据.内容 = table.concat( t, "\n")
        elseif 段数据.自定义 and self.取元素 then--#zdy/海龟
            段数据.类型 = 1
            段数据.内容 = self:_取元素('zdy',内容)
            段数据.宽度 = 段数据.内容.宽度 or 段数据.内容:取宽度()
            段数据.高度 = 段数据.内容.高度 or 段数据.内容:取高度()
        else
            段数据.内容 = 内容
        end
        if 段数据.类型 == 0 then
            段数据.宽度 = self._文字:取宽度(段数据.内容)
            段数据.高度 = self._文字:取高度(段数据.内容)
        end
    end
    return 段数据
end
function 丰富文本类:_检查样式(数据)
    if 数据:find('/') then
        local 主元素 = 数据:match("(.-)/")
        if not self:_检查元素(主元素) then--主元素
            return false
        end
        local r,t = {},{}
        for match in (数据.."/"):gmatch("(.-)/") do--按/分割
            local f = match:match("(%l*)")
            if f == 'xx' or f == 'sx' or f == 'bj' or f == 'pz' or --下划线,删除线,背景色,焦点文字色
                f == 'pb' or f == 'ht' or f == 'djy' or f == 'an' or --焦点背景色,回调标识,小段居右,文字按钮
                f == 'n' or f == 'jz' or f == 'jy' or f == 'ss' or  --换行,整行居中,整行居右,闪烁
                f == 'zdy' then --文本自定义
                table.insert(r, match)
            else
                table.insert(t, match)
            end
        end
        table.insert(r, table.concat( t, "/" ,2))--第1个是主元素
        return r,主元素
    end
end
function 丰富文本类:_解析(数据)
    local x      = 0
    local 行数据 = {x = 0,宽度 = 0,高度 = self._文字高度,内容 = ''}--行初始化

    for m in 数据:gmatch("(.-)#") do
        if m ~= '' then
            local 段内容,段数据 = {},{}--解析前,解析后
            local 段数量,主元素 = 0
            local r,主元素 = self:_检查样式(m)--是否多样式
            if r then
                段内容 = r
                段数量 = #段内容
            else
                主元素,段内容[2] = m:match(self._标识正则)
                --assert(主元素, 数据)
                if not self:_检查元素(主元素) then--和英文混合
                    local 标识 = 主元素
                    for i=self._标识长度-1,1,-1 do
                        if self:_检查元素(标识:sub(1,i)) then
                            主元素    = 标识:sub(1,i)
                            段内容[2] = 标识:sub(i+1)..段内容[2]
                            break
                        end
                    end
                end
                if not self:_检查元素(主元素) then--如果非法元素按默认处理
                    主元素    = self._默认元素
                    段内容[2] = '#'..m
                end
            end
            if 段数量 == 0 then
                if type(self:_取元素(主元素))=='table' then--非文本
                    段数据   = self:_生成段数据(x,self:_取元素(主元素))--动画
                    if 段内容[2] ~= '' then--表情文本混合
                        行数据   = self:_添加段数据(行数据,段数据)
                        x = 行数据.宽度
                        段数据 = self:_生成段数据(x,self._默认颜色,段内容[2])
                    end
                else
                    段数据 = self:_生成段数据(x,self:_取元素(主元素),段内容[2])
                end
            else--带有特殊样式的
                段数据 = self:_生成段数据(x,self:_取元素(主元素),"")
                for i,v in ipairs(段内容) do
                    段数据 = self:_生成样式(段数据,v)
                    if v == 'jz' then --居中
                        行数据.居中 = true
                    elseif v == 'jy' then --居右
                        行数据.居右 = true
                    end
                end
            end
            if 段数据.回调 then
                段数据.包围盒 = require("gge包围盒")(0,0,段数据.宽度,段数据.高度) end
            if 段数据.居右 then
                段数据.x = self._宽度-段数据.宽度 end
            行数据 = self:_添加段数据(行数据,段数据)
            x = 行数据.宽度
        end
    end
    if 行数据.居中 then 行数据.x = math.floor((self._宽度 -行数据.宽度)/2) end
    if 行数据.居右 then 行数据.x = self._宽度 -行数据.宽度 end
    self:_添加行数据(行数据)
end
function 丰富文本类:_添加段数据(行数据,段数据)
    if 段数据.类型 == 0 then--文本
        if 行数据.宽度 + 段数据.宽度 > self._宽度 then--大于就折行
            local 剩下长度 = math.floor((self._宽度 - 行数据.宽度)/self._文字宽度)
            local 剩下文本 = ''

            段数据.内容,剩下文本 = _取文本左边(段数据.内容,剩下长度)
            --段数据.折行 = true --用作判断下行高亮
            table.insert(行数据, 段数据)

            行数据.宽度 = self._宽度
            行数据      = self:_添加行数据(行数据)
            段数据      = _复制样式(段数据,剩下文本,self._文字:取宽度(剩下文本))--上一行的样式
            行数据 = self:_添加段数据(行数据,段数据)
        else
            --行数据.内容 = 行数据.内容..段数据.内容--无样式，用于搜索
            行数据.宽度 = 行数据.宽度 + 段数据.宽度
            table.insert(行数据, 段数据)--有样式
            --行数据.数量 = #行数据
        end
    else--对象(动画,图片等)
        if 段数据.宽度 < self._宽度 and 行数据.宽度 + 段数据.宽度 > self._宽度 then--大于就折行
            行数据.宽度 = self._宽度
            行数据      = self:_添加行数据(行数据)
            --if self._换行符 ~='' then 行数据   = self:_添加段数据(行数据,self:_生成段数据(self._默认颜色,self._换行符)) end
            段数据.x = 行数据.宽度
            行数据   = self:_添加段数据(行数据,段数据)
        else
            行数据.宽度 = 行数据.宽度 + 段数据.宽度
            table.insert(行数据, 段数据)
            --行数据.数量 = #行数据
            if 段数据.高度 > 行数据.高度 then
                行数据.高度 = 段数据.高度
            end
        end
    end
    return 行数据
end
function 丰富文本类:_添加行数据(行数据)
    table.insert(self._显示表, 行数据)
    self._显示表.高度  = self._显示表.高度 + 行数据.高度 + self._行间距
    if 行数据.宽度 > self._显示表.宽度 then
        self._显示表.宽度 = 行数据.宽度
    end
    return {x = 0,宽度 = 0,高度 = self._文字高度,内容 = ''}--行初始化
end
function 丰富文本类:_计算显示模式()
    if self._显示表.高度 > self._高度 then--倒显
        local 当前高度,行底部 = 0,self._行数量-self._滚动值
        self._目标值 = 1
        for i=行底部,1,-1 do
            当前高度 = 当前高度 + self._显示表[i].高度+self._行间距
            if 当前高度 >self._高度 then
                self._起始y = 当前高度-self._显示表[i].高度-self._行间距
                self._目标值 = i+1
                break
            elseif i==1 then
                self._起始y = 当前高度
            end
        end
        self._起始值 = 行底部
        self._递增值 = -1
    else
        self._滚动值 = 0
        self._起始值 = 1
        self._目标值 = self._行数量
        self._递增值 = 1
        self._起始y  = 0
    end
    self._显示模式 = (self._递增值 == 1)
end
--================================================================

function 丰富文本类:更新(x,y)

end
function 丰富文本类:显示(x,y)
    if type(x)=='table' then
        x,y = x.x or 0,x.y or 0
    end
    --self._包围盒:显示(x,y)
    if self._行数量 > 0 then
        self._碰撞表    = {}
        local 起始y = self._起始y
        local 画线  = 引擎.画线
        local 文字  = self._文字
        local 背景  = self._背景精灵
        for i=self._起始值,self._目标值,self._递增值 do
            if self._显示表[i] then
                local 行数据 = self._显示表[i]
                if (self._显示模式 and i ~= self._起始值 ) then--正显
                    起始y = 起始y  + self._行间距 + self._显示表[i-1].高度
                elseif (not self._显示模式 ) then--倒显
                    起始y = 起始y  - self._行间距 - 行数据.高度
                end
                for i,v in ipairs(行数据) do
                    local 当前x   = 行数据.x+x+v.x
                    local 当前y  = math.floor(起始y + y + (行数据.高度 - v.高度)/self._表情位置)
                    local 当前颜色 = self._全局颜色 or v.颜色
                    if v.背景颜色 then
                        背景:置区域(0,0,v.宽度,v.高度)
                            :置颜色(v.背景颜色)
                            :显示(当前x,当前y)
                    end

                    if v.回调 then
                        table.insert(self._碰撞表, v)
                        v.包围盒:置坐标(当前x ,当前y)
                        --v.包围盒:显示()
                        if v.包围盒:检查点(引擎.取鼠标坐标()) then
                            if v.碰撞颜色 then 当前颜色 = v.碰撞颜色 end
                            if v.碰撞背色 then
                            背景:置区域(0,0,v.宽度,v.高度)
                                :置颜色(v.碰撞背色)
                                :显示(当前x,当前y)
                            end
                            if v.按钮 and self.左键按下 then
                                当前x ,当前y = 当前x +1,当前y+1
                            end
                        end
                    end
                    if v.闪烁时间 then
                        v.闪烁时间 = v.闪烁时间 + 引擎.取帧时间()
                        if v.闪烁时间 >= 0.5 then
                            v.闪烁时间 = 0
                            v.闪烁可见 = not v.闪烁可见
                        end
                    end
                    if not v.闪烁时间 or v.闪烁可见 then
                        if v.类型 == 0 then--文本
                            if v.下划线 then
                                画线(当前x,当前y+v.高度-1, 当前x+v.宽度,当前y+v.高度-1, 当前颜色)
                            end
                            if v.删除线 then
                                画线(当前x,当前y+v.高度-5, 当前x+v.宽度,当前y+v.高度-5, 当前颜色)
                            end
                            文字:置颜色(当前颜色)
                            文字:显示(当前x ,当前y,v.内容)
                        elseif v.类型 == 1 then--对象
                            v.内容:显示(当前x ,当前y)
                        end
                    end
                end
            end
        end
    end
end

function 丰富文本类:检查按钮(x,y)
    for i,v in ipairs(self._碰撞表) do
        if v.包围盒:检查点(x,y) then
            if v.回调 == '' then
                return v.内容
            end
            return v.回调
        end
    end
end
return 丰富文本类



